package com.alibaba.citrus.cr.sales.plan.facade.msg;

import com.alibaba.acm.shaded.com.alibaba.metrics.StringUtils;
import com.alibaba.citrus.cr.common.annotation.EpochTransactional;
import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.common.exception.ActivityException;
import com.alibaba.citrus.cr.common.exception.FacadeException;
import com.alibaba.citrus.cr.common.util.CalculatePercentage;
import com.alibaba.citrus.cr.sales.plan.api.setting.SalesPlanStrategyDetailQueryService;
import com.alibaba.citrus.cr.sales.plan.contants.SalesPlanConstants;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.DispatchPlanScItemRequest;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.QueryPlanScItemExtendRequest;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.QueryPlanScItemStatRequest;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.QuerySalesPlanRequest;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.QuerySalesPlanStrategyListRequest;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.SalesOrgRatioDTO;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.SalesPlanBatchQueryRequest;
import com.alibaba.citrus.cr.sales.plan.dto.api.response.SalesPlanStrategyDetailResponse;
import com.alibaba.citrus.cr.sales.plan.facade.service.SalesPlanCommonService;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesPlanCheckStatusEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesPlanModelEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesPlanStatusEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesStatBizTypeEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.StatPoolTypeEnum;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanLineRepository;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanOrganizationRepository;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanRepository;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanScItemExtendRepository;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanScItemStatRepository;
import com.alibaba.citrus.cr.sales.plan.repository.request.QuerySpecifiedDepthRepoRequest;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanLineSDO;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanSDO;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanScItemExtendSDO;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanStatScItemSDO;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanStrategyDetailSDO;
import com.alibaba.citrus.cr.sales.plan.api.salesplan.publish.SalesPlanPublishWriteServiceNew;
import com.alibaba.citrus.cr.sales.plan.msg.SalesPlanResolveMessageConsumer;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.page.PageResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.middleware.cache.runtime.service.EpochCacheService;
import com.alibaba.lattice2.epoch.middleware.mq.runtime.EpochMessageService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.contants.BcOrderConstants;
import com.epoch.app.bcorder.model.dto.BatchDeletePlanScItemExtendRequest;
import com.epoch.app.bcorder.model.dto.OrganizationSDO;
import com.epoch.app.bcorder.service.SalesPlanService;
import com.epoch.app.crplatformenhance.enums.OrganizationTypeEnum;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 月度计划分解消息
 * @author suqing.tjf
 * @date 2022年01月18日10:20:01
 */
@Component
public class SalesPlanResolveMessageConsumerImpl implements SalesPlanResolveMessageConsumer {

    private final Log log = Log.getLogger(SalesPlanResolveMessageConsumerImpl.class);

    @Resource
    private SalesPlanRepository salesPlanRepository;

    @Resource
    private SalesPlanScItemExtendRepository salesPlanScItemExtendRepository;

    @Resource
    private SalesPlanScItemStatRepository salesPlanScItemStatRepository;

    @Resource
    private SalesPlanLineRepository salesPlanLineRepository;

    @Resource
    private SalesPlanCommonService salesPlanCommonService;

    @Resource
    private SalesPlanStrategyDetailQueryService salesPlanStrategyDetailQueryService;

    @Resource
    private SalesPlanOrganizationRepository organizationRepository;

    @Resource
    private EpochMessageService messageService;

    @Resource
    private SalesPlanService salesPlanService;

    @Resource
    private SalesPlanPublishWriteServiceNew salesPlanPublishWriteServiceNewImpl;

    @Resource
    private EpochCacheService epochCacheService;

    /**
     * 部门任务分解
     *
     * @param message
     */
    @FacadeInvoker
    @Override
    public Result<Boolean> resolveDepartmentTask(String message) {
        log.info("SalesPlanResolveMessageConsumerImpl.resolveDepartmentTask message:" + message);
        DispatchPlanScItemRequest dispatchPlanScItemRequest = null;
        try {
            if (StringUtils.isBlank(message)) {
                log.error("月度计划部门任务量分解的消息体为空");
                return Result.success(null, "月度计划部门任务量分解接受的消息为空");
            }
            dispatchPlanScItemRequest = JSONObject.parseObject(message, DispatchPlanScItemRequest.class);
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            String flag = BcOrderConstants.SALES_PLAN_PUBLICE_CHANE_FLAG();
            if (StringUtils.isNotBlank(flag) && "1".equals(flag)) {
                salesPlanPublishWriteServiceNewImpl.dispatchPlanScItemForDepartmentNew(dispatchPlanScItemRequest);
            } else {
                dispatchPlanScItemForDepartmentNew(dispatchPlanScItemRequest);
            }
            stopWatch.stop();
            log.info("SalesPlanPublishWriteServiceImpl#dispatchPlanScItemForDepartment planId=" + dispatchPlanScItemRequest.getPlanId() + " elapsed time:" + stopWatch.getTotalTimeMillis() + "ms");
        } catch (FacadeException e) {
            log.error("SalesPlanPublishWriteServiceImpl#dispatchPlanScItemForDepartment_fail  ", e);
        } catch (Exception e) {
            log.error("SalesPlanPublishWriteServiceImpl#dispatchPlanScItemForDepartment_occur_error  ", e);
        } finally {
            if (null != dispatchPlanScItemRequest) {
                // 执行完清理缓存
                epochCacheService.remove(BcOrderConstants.REDIS_CACHE_CODE(), Lists.newArrayList(SalesPlanConstants.getDispatchPlanScItemForDepartmentKey(dispatchPlanScItemRequest.getPlanId())));
            }
        }
        return Result.success(null, "部分任务量分解已完成");
    }

    /**
     * 客户任务分解
     *
     * @param message
     */
    @Override
    public Result<Boolean> resolveCustomerTask(String message) {
        log.info("SalesPlanResolveMessageConsumerImpl.resolveCustomerTask message:" + message);
        DispatchPlanScItemRequest dispatchPlanScItemRequest = null;
        try {
            if (StringUtils.isBlank(message)) {
                log.error("月度计划客户任务量分解的消息体为空");
                return Result.success(null, "月度计划客户任务量分解接受的消息为空");
            }
            dispatchPlanScItemRequest = JSONObject.parseObject(message, DispatchPlanScItemRequest.class);
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            String flag = BcOrderConstants.SALES_PLAN_PUBLICE_CHANE_FLAG();
            if (StringUtils.isNotBlank(flag) && "1".equals(flag)) {
                salesPlanPublishWriteServiceNewImpl.dispatchPlanScItemForCustomerNew(dispatchPlanScItemRequest);
            } else {
                dispatchPlanScItemForCustomerNew(dispatchPlanScItemRequest);
            }
            stopWatch.stop();
            log.info("SalesPlanPublishWriteServiceImpl#dispatchPlanScItemForCustomer planId=" + dispatchPlanScItemRequest.getPlanId() + " elapsed time:" + stopWatch.getTotalTimeMillis() + "ms");
        } catch (FacadeException e) {
            log.error("SalesPlanPublishWriteServiceImpl#dispatchPlanScItemForCustomer_fail ", e);
        } catch (Exception e) {
            log.error("SalesPlanPublishWriteServiceImpl#dispatchPlanScItemForCustomer_occur_error ", e);
        } finally {
            if (null != dispatchPlanScItemRequest) {
                // 执行完清理缓存
                epochCacheService.remove(BcOrderConstants.REDIS_CACHE_CODE(), Lists.newArrayList(SalesPlanConstants.getDispatchPlanScItemForCustomerKey(dispatchPlanScItemRequest.getPlanId())));
            }
        }
        return Result.success(null, "客户任务量分解已完成");
    }

    private void dispatchPlanScItemForCustomerNew(DispatchPlanScItemRequest dispatchPlanScItemRequest) {
        //0、相关参数校验
        String planId = dispatchPlanScItemRequest.getPlanId();
        SalesPlanSDO salesPlanSDO = salesPlanCommonService.checkSalesPlan(planId);
        checkParam(dispatchPlanScItemRequest);
        // 所有部门
        QueryPlanScItemExtendRequest departmentRequest = new QueryPlanScItemExtendRequest();
        departmentRequest.setPlanId(Long.valueOf(planId));
        departmentRequest.setBizType(SalesStatBizTypeEnum.SALES_DEPARTMENT.getBizType());
        departmentRequest.setPoolType(Objects.toString(StatPoolTypeEnum.SC_ITEM.getPoolType()));
        departmentRequest.setModel(SalesPlanModelEnum.PLAN_MODEL.getModel());
        // 查询部门任务量已经发布过的
        departmentRequest.setStatus(SalesPlanStatusEnum.PUBLISHED.getCode());
        log.info("查询已经发布的部门任务量参数{}", JSON.toJSONString(departmentRequest));
        List<SalesPlanScItemExtendSDO> salesPlanScItemExtendSDOList = salesPlanScItemExtendRepository.batchQueryPlanScItemExtend(departmentRequest);
        log.info("查询已经发布的部门任务量结果{}", JSON.toJSONString(salesPlanScItemExtendSDOList));

/*        // 部门任务量的汇总
        Map<String, List<SalesPlanScItemExtendSDO>> departmentMap = salesPlanScItemExtendSDOList
                .stream().collect(Collectors.groupingBy(salesPlanScItemExtendSDO -> salesPlanScItemExtendSDO.getScItemId()));*/
        if (CollectionUtils.isEmpty(salesPlanScItemExtendSDOList)) {
            throw new FacadeException("OTS-02-004-01-16-016");
        }
        for (SalesPlanScItemExtendSDO scItemExtendSDO : salesPlanScItemExtendSDOList) {
            SalesPlanBatchQueryRequest request = new SalesPlanBatchQueryRequest();
            request.setPlanId(Long.valueOf(planId));
            request.setScItemId(scItemExtendSDO.getScItemId());
            request.setOrgSalesDepartmentCode(scItemExtendSDO.getBizId());
            List<SalesPlanLineSDO> salesPlanLineSDOS = salesPlanLineRepository.batchQueryDetail(request);
/*            SalesPlanLineSDO planLineSDORemove = salesPlanLineSDOS.remove(0);
            List<SalesPlanScItemExtendSDO> salesPlanScItemExtendSDOS = departmentMap.get(scItemExtendSDO.getScItemId());
            if (CollectionUtils.isEmpty(salesPlanScItemExtendSDOS)) {
                continue;
            }
            int departmentSum = salesPlanScItemExtendSDOS.stream().mapToInt(SalesPlanScItemExtendSDO::getTaskCount).sum();*/
            Integer monthCountByDepartment = scItemExtendSDO.getMonthCount();
            Integer monthFirstCountByDepartment = scItemExtendSDO.getMonthFirstCount();
            Integer monthMiddleCountByDepartment = scItemExtendSDO.getMonthMiddleCount();
            Integer monthLastCountByDepartment = scItemExtendSDO.getMonthLastCount();
//            List<SalesPlanLineSDO> salesPlanLineSDONew = new ArrayList<>();
            for (SalesPlanLineSDO salesPlanLineSDO : salesPlanLineSDOS) {
                //1、上旬
                // 客户上旬提报量
                Integer monthFirstCount = salesPlanLineSDO.getMonthFirstCount();
                //上旬客户理论回复占比  （客户提报量/部门提报量）
                BigDecimal bigDecimalFirst = CalculatePercentage.retainTwo(monthFirstCount.longValue(), monthFirstCountByDepartment.longValue());
                BigDecimal firstReturnRate = bigDecimalFirst.multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_HALF_UP);
                //上旬客户理论任务量    （部门任务量*理论回复占比）
                Integer monthFirstReturnCountByCustomer = new BigDecimal(scItemExtendSDO.getMonthFirstTaskCount())
                        .multiply(firstReturnRate).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                salesPlanLineSDO.setMonthFirstReturnCount(monthFirstReturnCountByCustomer);
                salesPlanLineSDO.setMonthFirstTaskCount(monthFirstReturnCountByCustomer);
                //2、中旬
                Integer monthMiddleCount = salesPlanLineSDO.getMonthMiddleCount();
                //中旬客户理论回复占比  （客户提报量/部门提报量）
                BigDecimal bigDecimalMiddle = CalculatePercentage.retainTwo(monthMiddleCount.longValue(), monthMiddleCountByDepartment.longValue());
                BigDecimal middleReturnRate = bigDecimalMiddle.multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_HALF_UP);
                //中旬客户理论任务量    （部门任务量*理论回复占比）
                Integer monthMiddleReturnCountByCustomer = new BigDecimal(scItemExtendSDO.getMonthMiddleTaskCount())
                        .multiply(middleReturnRate).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                salesPlanLineSDO.setMonthMiddleReturnCount(monthMiddleReturnCountByCustomer);
                salesPlanLineSDO.setMonthMiddleTaskCount(monthMiddleReturnCountByCustomer);

                //3、下旬
                Integer monthLastCount = salesPlanLineSDO.getMonthLastCount();
                //下旬客户理论回复占比  （客户提报量/部门提报量）
                BigDecimal bigDecimalLast = CalculatePercentage.retainTwo(monthLastCount.longValue(), monthLastCountByDepartment.longValue());
                BigDecimal lastReturnRate = bigDecimalLast.multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_HALF_UP);
                //下旬客户理论任务量    （部门任务量*理论回复占比）
                Integer monthLastReturnCountByCustomer = new BigDecimal(scItemExtendSDO.getMonthLastTaskCount())
                        .multiply(lastReturnRate).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                salesPlanLineSDO.setMonthLastReturnCount(monthLastReturnCountByCustomer);
                salesPlanLineSDO.setMonthLastTaskCount(monthLastReturnCountByCustomer);
                // 客户总任务量
                Integer monthReturnCountByCustomer = monthFirstReturnCountByCustomer + monthMiddleReturnCountByCustomer + monthLastReturnCountByCustomer;
                salesPlanLineSDO.setTaskCount(monthReturnCountByCustomer);
                salesPlanLineSDO.setBeforeTaskMoney(salesPlanLineSDO.getTaskCount() * salesPlanLineSDO.getCostInsuranceFreight());
                salesPlanLineSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                salesPlanLineSDO.calculateTaskSatisfaction();
                //到岸折前金额
                long outboundPrice = Objects.nonNull(salesPlanLineSDO.getOutboundPrice()) ? salesPlanLineSDO.getOutboundPrice() : 0;
                long beforeMonthOutboundMoney = salesPlanLineSDO.getTaskCount() * outboundPrice;
                salesPlanLineSDO.setBeforeMonthOutboundMoney(beforeMonthOutboundMoney);
                //到岸折后金额 到岸折后金额=到岸折前金额*(1-预估价格折扣率)
                salesPlanLineSDO.calculateMonthOutboundMoney(salesPlanSDO.getEstimateDiscount());
//                // 将除了第一个，剩余变更的客户任务放到list中
//                salesPlanLineSDONew.add(salesPlanLineSDO);
                // 明细状态暂不更细
//                salesPlanLineSDO.setStatus(SalesPlanStatusEnum.TO_BE_PUBLISHED.getCode());
                // 更新计划明细
                salesPlanLineRepository.edit(salesPlanLineSDO);
            }
//
//            if (CollectionUtils.isNotEmpty(salesPlanLineSDONew)) {
//                int customerSum = salesPlanLineSDONew.stream().mapToInt(SalesPlanLineSDO::getTaskCount).sum();
//                int diff = departmentSum - customerSum;
//                Integer monthFirstReturnCount = planLineSDORemove.getMonthFirstReturnCount();
//                Integer monthFirstTaskCount = planLineSDORemove.getMonthFirstTaskCount();
//                Integer taskCount = planLineSDORemove.getTaskCount();
//                planLineSDORemove.setMonthFirstReturnCount(monthFirstReturnCount + diff);
//                planLineSDORemove.setMonthFirstTaskCount(monthFirstTaskCount + diff);
//                planLineSDORemove.setTaskCount(taskCount);
//                // 更新这一条月度计划明细
//                salesPlanLineRepository.edit(planLineSDORemove);
//            }
        }
        // 更新发布状态为已生成客户任务量
        SalesPlanSDO updateCheckStatusSalesPlanSDO = new SalesPlanSDO();
        updateCheckStatusSalesPlanSDO.setId(Long.valueOf(planId));
        updateCheckStatusSalesPlanSDO.setCheckStatus(SalesPlanCheckStatusEnum.DECOMPOSE_CUSTOMER_TASK.getCode());
        salesPlanRepository.editSalesPlan(updateCheckStatusSalesPlanSDO);

        try {
            // 生成客户任务量的时候，触发一下月度计划汇总
            log.info("dispatchPlanScItemForCustomer_salesPlanCollectListener{}", planId);
            Boolean aBoolean = messageService.sendMessage("sales_plan_publish_message", "CR_SALES_PLAN_V2", "salesPlan_collect", planId);
        } catch (Exception e) {
            log.error("月度计划生成客户任务量触发汇总的消息发送异常", e);
        }
    }

    /**
     * 生成部门任务量
     *
     * @param dispatchPlanScItemRequest
     * @return
     */
    private Boolean dispatchPlanScItemForDepartmentNew(DispatchPlanScItemRequest dispatchPlanScItemRequest) {
        // 0、基本参数校验
        checkParam(dispatchPlanScItemRequest);
        // 0.5 先删除在新增
        BatchDeletePlanScItemExtendRequest batchDeletePlanScItemExtendRequest = new BatchDeletePlanScItemExtendRequest();
        batchDeletePlanScItemExtendRequest.setPlanId(dispatchPlanScItemRequest.getPlanId());
        batchDeletePlanScItemExtendRequest.setBizType(2);
        batchDeletePlanScItemExtendRequest.setPoolType(2);
        log.info("删除部门回复量extend请求入参{}", JSONObject.toJSONString(batchDeletePlanScItemExtendRequest));
        salesPlanService.batchDeletePlanScItemExtend(batchDeletePlanScItemExtendRequest);
        // 1、根据计划id查询  计划是否是待发布状态(20220915去掉)
        String planId = dispatchPlanScItemRequest.getPlanId();
        SalesPlanSDO salesPlanSDO = checkPlan(planId);
        // 2、查询分子公司的货品回复量
        QueryPlanScItemExtendRequest queryPlanScItemExtendRequest = new QueryPlanScItemExtendRequest();
        queryPlanScItemExtendRequest.setPlanId(Long.valueOf(planId));
        queryPlanScItemExtendRequest.setBizType(SalesStatBizTypeEnum.BUSINESS_UNIT.getBizType());
        queryPlanScItemExtendRequest.setBizId(salesPlanSDO.getOrgBusinessUnitCode());
        queryPlanScItemExtendRequest.setPoolType(Objects.toString(StatPoolTypeEnum.SC_ITEM.getPoolType()));
        queryPlanScItemExtendRequest.setModel(SalesPlanModelEnum.PLAN_MODEL.getModel());
        log.info("分子公司的货品回复量查询参数{}", JSON.toJSONString(queryPlanScItemExtendRequest));
        List<SalesPlanScItemExtendSDO> salesPlanScItemExtendSDOList = salesPlanScItemExtendRepository.batchQueryPlanScItemExtend(queryPlanScItemExtendRequest);
        log.info("分子公司的货品回复量查询结果{}", JSON.toJSONString(salesPlanScItemExtendSDOList));
        if (CollectionUtils.isEmpty(salesPlanScItemExtendSDOList)) {
            throw new FacadeException("OTS-02-004-01-15-009");
        }
        List<SalesPlanScItemExtendSDO> planScItemExtendSDOAllList = new ArrayList<>();
        // 遍历分子公司的计划货品
        for (SalesPlanScItemExtendSDO salesPlanScItemExtendSDO : salesPlanScItemExtendSDOList) {
            // 业务单元货品计划提报量
            Integer monthCount = salesPlanScItemExtendSDO.getMonthCount();
            // 业务单元货品上旬回复量
            Integer monthFirstReturnCount = salesPlanScItemExtendSDO.getMonthFirstReturnCount();
            // 业务单元货品中旬回复量
            Integer monthMiddleReturnCount = salesPlanScItemExtendSDO.getMonthMiddleReturnCount();
            // 业务单元货品下旬回复量
            Integer monthLastReturnCount = salesPlanScItemExtendSDO.getMonthLastReturnCount();
            // 业务单元货品回复量总和
            Integer monthReturnCount = monthFirstReturnCount + monthMiddleReturnCount + monthLastReturnCount;
            log.info("分子公司遍历的货品{}", JSON.toJSONString(salesPlanScItemExtendSDO));

            // 比较业务单元货品回复量和货品计划提报量的大小
            // 回复量大于提报量，按提报量向下回复（原计划三旬提报量就是回复量，也就是合同量）
            log.info("分子公司遍历的货品的提报量={},回复量={}", monthCount, monthReturnCount);
            if (monthReturnCount >= monthCount) {
                //  公司级别的每个货品
                String scItemId = salesPlanScItemExtendSDO.getScItemId();
                // 查询该公司下  所有部门下的该一个货品
                QueryPlanScItemStatRequest queryPlanScItemStatRequest = new QueryPlanScItemStatRequest();
                queryPlanScItemStatRequest.setPlanId(Long.parseLong(planId));
                queryPlanScItemStatRequest.setScItemId(scItemId);
                queryPlanScItemStatRequest.setBizType(SalesStatBizTypeEnum.SALES_DEPARTMENT.getBizType());
                queryPlanScItemStatRequest.setPoolType(Objects.toString(StatPoolTypeEnum.SC_ITEM.getPoolType()));
                queryPlanScItemStatRequest.setStart(0);
                queryPlanScItemStatRequest.setLimit(1000);
                PageResult<List<SalesPlanStatScItemSDO>> pageResult = salesPlanScItemStatRepository.batchQueryPlanScItemByBizId(queryPlanScItemStatRequest);
                if (null == pageResult || CollectionUtils.isEmpty(pageResult.getContent())) {
                    continue;
                }
                List<SalesPlanStatScItemSDO> departmentScItemExtendList = pageResult.getContent();
                departmentScItemExtendList.forEach(departmentScItem -> {
                    SalesPlanScItemExtendSDO extendSDO = new SalesPlanScItemExtendSDO();
                    BeanUtils.copyProperties(departmentScItem, extendSDO);
                    // 根据上旬计划量设置上旬回复量和任务量
                    Integer monthFirstCount = departmentScItem.getMonthFirstCount();
                    extendSDO.setMonthFirstReturnCount(monthFirstCount);
                    extendSDO.setMonthFirstTaskCount(monthFirstCount);
                    // 根据中旬计划量设置中旬回复量和任务量
                    Integer monthMiddleCount = departmentScItem.getMonthMiddleCount();
                    extendSDO.setMonthMiddleReturnCount(monthMiddleCount);
                    extendSDO.setMonthMiddleTaskCount(monthMiddleCount);
                    // 根据中旬计划量设置中旬回复量和任务量
                    Integer monthLastCount = departmentScItem.getMonthLastCount();
                    extendSDO.setMonthLastReturnCount(monthLastCount);
                    extendSDO.setMonthLastTaskCount(monthLastCount);
                    // 任务量总和就是提报量
                    extendSDO.setTaskCount(departmentScItem.getMonthCount());
                    // 计算折前任务金额
                    extendSDO.setBeforeTaskMoney(extendSDO.getTaskCount() * extendSDO.getCostInsuranceFreight());
                    // 计算折后任务金额
                    extendSDO.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                    extendSDO.calculateTaskSatisfaction();
                    extendSDO.setId(null);
                    extendSDO.setModel(SalesPlanModelEnum.PLAN_MODEL.getModel());
                    extendSDO.setModelId(planId);
                    // 更新状态为待发布
                    extendSDO.setStatus(SalesPlanStatusEnum.TO_BE_PUBLISHED.getCode());
                    planScItemExtendSDOAllList.add(extendSDO);
                });
            }
            //回复量小于提报量，按回复量向部门回复（使用策略计算公式重新计算）
            else {
                //  公司级别的每个货品
                String scItemId = salesPlanScItemExtendSDO.getScItemId();
                // 查询该公司下  该销售组织下的该一个货品   （通过公司查不同组织的占比(策略)，就能拿到组织id，这里遍历数据，取组织id，当然一个组织对应一个占比）
                // 2.5、查询分子公司（业务单元）的销售组织占比 来源于策略
                QuerySalesPlanStrategyListRequest querySalesPlanStrategyListRequest = new QuerySalesPlanStrategyListRequest();
                querySalesPlanStrategyListRequest.setOrgBusinessCode(salesPlanSDO.getOrgBusinessUnitCode());
                // 目前策略类型都是1(表示计划回复策略)
                querySalesPlanStrategyListRequest.setType(1);
                log.info("查询分子公司的回复策略参数{}", JSON.toJSONString(querySalesPlanStrategyListRequest));
                Result<SalesPlanStrategyDetailResponse> detailResponseResult =
                        salesPlanStrategyDetailQueryService.getSalesPlanStrategyDetail(querySalesPlanStrategyListRequest);
                log.info("查询分子公司的回复策略结果{}", JSON.toJSONString(detailResponseResult));
                if (null == detailResponseResult || null == detailResponseResult.getResult()) {
                    throw new FacadeException("OTS-02-004-01-15-010");
                }
                SalesPlanStrategyDetailResponse salesPlanStrategyDetailResponse = detailResponseResult.getResult();
                // 拿到组织占比策略
                List<SalesOrgRatioDTO> salesOrgRatioDTOList = salesPlanStrategyDetailResponse.getSalesOrgRatioDTOList();
                if (CollectionUtils.isEmpty(salesOrgRatioDTOList)) {
                    throw new FacadeException("OTS-02-004-01-15-011");
                }
                // 遍历销售组织，去计算各自的占比
                for (SalesOrgRatioDTO salesOrgRatioDTO : salesOrgRatioDTOList) {
                    // 根据策略获取组织id
                    String organizationId = salesOrgRatioDTO.getSalesOrgCode();
                    // 查询该组织下的所有部门
                    QuerySpecifiedDepthRepoRequest querySpecifiedDepthRepoRequest = new QuerySpecifiedDepthRepoRequest();
                    querySpecifiedDepthRepoRequest.setOrganizationId(organizationId);
                    querySpecifiedDepthRepoRequest.setOrganizationType(OrganizationTypeEnum.SALES_DEPARTMENT.getCode());
                    List<OrganizationSDO> departmentSDOForOrg = null;
                    departmentSDOForOrg = organizationRepository.querySpecifiedDepth(querySpecifiedDepthRepoRequest);
                    // 拿到组织占比
                    Integer orgRatio = salesOrgRatioDTO.getRatio();
                    BigDecimal orgRatioNew = new BigDecimal(orgRatio).multiply(new BigDecimal(0.0001)).setScale(2, BigDecimal.ROUND_HALF_UP);
                    // 查询组织下的计划货品
                    QueryPlanScItemStatRequest queryPlanScItemStatRequest = new QueryPlanScItemStatRequest();
                    queryPlanScItemStatRequest.setPlanId(Long.valueOf(planId));
                    queryPlanScItemStatRequest.setBizType(SalesStatBizTypeEnum.SALES_ORGANIZATION.getBizType());
                    queryPlanScItemStatRequest.setPoolType(Objects.toString(StatPoolTypeEnum.SC_ITEM.getPoolType()));
                    queryPlanScItemStatRequest.setScItemId(scItemId);
                    queryPlanScItemStatRequest.setBizId(organizationId);
                    queryPlanScItemStatRequest.setStart(0);
                    queryPlanScItemStatRequest.setLimit(1000);
                    // 下面就能查到该组织下的该货品数据 按理说只有一条
                    log.info("查询分子公司下组织的汇总数据参数{}", JSON.toJSONString(queryPlanScItemStatRequest));
                    PageResult<List<SalesPlanStatScItemSDO>> pageResult = salesPlanScItemStatRepository.batchQueryPlanScItemByBizId(queryPlanScItemStatRequest);
                    List<SalesPlanStatScItemSDO> salesPlanStatScItemOrganizationSDOList = pageResult.getContent();
                    log.info("查询分子公司下组织的汇总数据结果{}", JSON.toJSONString(salesPlanStatScItemOrganizationSDOList));
                    //一个销售组织下一个货品只有一条数据
                    SalesPlanStatScItemSDO salesPlanStatScItemOrganizationSDO = salesPlanStatScItemOrganizationSDOList.get(0);
                    if (Objects.isNull(salesPlanStatScItemOrganizationSDO)) {
                        continue;
                    }
                    // 根据业务单元的回复量总和*占比  计算销售组织的回复量
                    Integer monthOrganizationReturnCount = new BigDecimal(monthReturnCount).multiply(orgRatioNew).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                    // 销售组织上旬回复量
                    int monthFirstOrganizationReturnCount = new BigDecimal(monthFirstReturnCount).multiply(orgRatioNew).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                    // 销售组织中旬回复量
                    int monthMiddleOrganizationReturnCount = new BigDecimal(monthMiddleReturnCount).multiply(orgRatioNew).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                    // 销售组织下旬回复量
                    // TODO
                    int monthLastOrganizationReturnCount = monthOrganizationReturnCount - monthFirstOrganizationReturnCount - monthMiddleOrganizationReturnCount;
                    // TODO
                    // int monthLastOrganizationReturnCount = new BigDecimal(monthLastReturnCount).multiply(orgRatioNew).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                    // 将计算到的销售组织的回复量 set到对象里返回、 就是任务量
                    salesPlanStatScItemOrganizationSDO.setTaskCount(monthOrganizationReturnCount);

                    // 拿到该销售组织下的货品
                    String scItemIdByOrganization = salesPlanStatScItemOrganizationSDO.getScItemId();

                    // 查询该公司下  该部门下的该一个货品   （通过公司查不同部门的策略，就能拿到部门id，这里遍历数据，取部门id，当然一个部门对应一个策略）
                    // 拿到部门策略
                    List<SalesPlanStrategyDetailSDO> salesPlanStrategyDetailDepartmentList = salesPlanStrategyDetailResponse.getSalesPlanStrategyDetailDepartmentList();
                    if (CollectionUtils.isEmpty(salesPlanStrategyDetailDepartmentList)) {
                        throw new FacadeException("OTS-02-004-01-15-012");
                    }
                    // 取出部门id列表
                    List<String> departmentIdList = salesPlanStrategyDetailDepartmentList.stream().map(SalesPlanStrategyDetailSDO::getReplyTargetId).collect(Collectors.toList());
                    //批量查询部门的货品提报量
                    QueryPlanScItemStatRequest queryPlanScItemStatRequestForDepartment = new QueryPlanScItemStatRequest();
                    queryPlanScItemStatRequestForDepartment.setPlanId(Long.valueOf(planId));
                    queryPlanScItemStatRequestForDepartment.setBizType(SalesStatBizTypeEnum.SALES_DEPARTMENT.getBizType());
                    queryPlanScItemStatRequestForDepartment.setPoolType(Objects.toString(StatPoolTypeEnum.SC_ITEM.getPoolType()));
                    queryPlanScItemStatRequestForDepartment.setScItemId(scItemIdByOrganization);
                    queryPlanScItemStatRequestForDepartment.setBizIds(departmentIdList);
                    queryPlanScItemStatRequestForDepartment.setStart(0);
                    queryPlanScItemStatRequestForDepartment.setLimit(1000);
                    log.info("查询分子公司下配置策略的所有部门的汇总数据参数{}", JSON.toJSONString(queryPlanScItemStatRequestForDepartment));
                    PageResult<List<SalesPlanStatScItemSDO>> pageResult1 = salesPlanScItemStatRepository.batchQueryPlanScItemByBizId(queryPlanScItemStatRequestForDepartment);
                    List<SalesPlanStatScItemSDO> salesPlanStatScItemSDOList = pageResult1.getContent();
                    log.info("查询分子公司下配置策略的所有部门的汇总数据结果{}", JSON.toJSONString(salesPlanStatScItemSDOList));
                    // key :departmentId  value:SalesPlanStatScItemSDO
                    Map<String, SalesPlanStatScItemSDO> map = salesPlanStatScItemSDOList.stream().collect(Collectors.toMap(SalesPlanStatScItemSDO::getBizId, item -> item));
                    if (MapUtils.isEmpty(map)) {
                        throw new FacadeException("OTS-02-004-01-15-013");
                    }
                    // 1 遍历部门策略，根据策略因子计算部门的理论回复量（当然要判断在不在此销售组织下） 生成一个list（部门的理论回复量汇总，部门id）上中下
                    // 2 将部门的理论回复量加起来是此销售组织的理论回复量汇总
                    // 3 遍历生成的list，计算每个部门的理论回复占比= 部门理论回复量/组织理论回复量汇总
                    // 4 在遍历3的同时，计算部门实际回复量（也就是初始任务量）= 组织实际回复量（策略占比来的）* 部门的理论回复占比

                    List<Map<String, Map<String, Integer>>> list = new ArrayList<>();
                    Map<String, Integer> theoryReturnCountSum = new HashMap<String, Integer>();
                    // 部门上旬理论回复量汇总
                    Integer theoryFirstReturnCountSum = 0;
                    // 部门中旬理论回复量汇总
                    Integer theoryMiddleReturnCountSum = 0;
                    // 部门下旬理论回复量汇总
                    Integer theoryLastReturnCountSum = 0;
                    // 部门月度理论回复量汇总
                    Integer theoryMonthReturnCountSum = 0;
                    for (SalesPlanStrategyDetailSDO departmentStrategy1 : salesPlanStrategyDetailDepartmentList) {
                        Map<String, Map<String, Integer>> departmentMap = new HashMap<>();
                        // 部门的三旬理论回复量
                        Map<String, Integer> departmentMonthMap = new HashMap<>();
                        // 部门id
                        String departmentId = departmentStrategy1.getReplyTargetId();
                        // 筛选有策略的部门是否在该组织下
                        boolean flag = departmentSDOForOrg.stream().anyMatch(d -> departmentId.equals(d.getId()));
                        if (!flag) {
                            continue;
                        }

                        // 提报量因子
                        Integer firstWeightRatio = departmentStrategy1.getFirstWeightRatio();
                        // 合同量因子
                        Integer secondWeightRatio = departmentStrategy1.getSecondWeightRatio();
                        SalesPlanStatScItemSDO salesPlanStatScItemSDO = map.get(departmentId);
                        // 部门策略配置多了，实际这个部门没有提报的情况
                        if (Objects.isNull(salesPlanStatScItemSDO)) {
                            continue;
                        }
                        SalesPlanScItemExtendSDO salesPlanScItemExtendSDONew = new SalesPlanScItemExtendSDO();
                        BeanUtils.copyProperties(salesPlanStatScItemSDO, salesPlanScItemExtendSDONew);
                        // 上旬提报量*权重+上旬合同量*权重 合同量根据三询均衡拆分
                        Integer monthContractCount = salesPlanScItemExtendSDONew.getMonthContractCount();
                        // 月份三旬合同量map
                        Map<String, Integer> balanceContractMap = getBalanceContract(salesPlanSDO, monthContractCount);
                        // 一、 上旬
                        //上旬合同量
                        Integer monthFirstContractCount = balanceContractMap.get("monthFirstContractCount");
                        //上旬提报量
                        Integer monthFirstCount = salesPlanScItemExtendSDONew.getMonthFirstCount();
                        // 上旬部门理论回复量
                        Integer theoryFirstReturnCount = getTheoryReturnCount(monthFirstCount, monthFirstContractCount, firstWeightRatio, secondWeightRatio);
                        departmentMonthMap.put("theoryFirstReturnCount", theoryFirstReturnCount);
                        // 上旬理论回复量求和
                        theoryFirstReturnCountSum = theoryFirstReturnCountSum + theoryFirstReturnCount;
                        // 二、 中旬
                        //中旬合同量
                        Integer monthMiddleContractCount = balanceContractMap.get("monthMiddleContractCount");
                        //中旬提报量
                        Integer monthMiddleCount = salesPlanScItemExtendSDONew.getMonthMiddleCount();
                        // 中旬部门理论回复量
                        Integer theoryMiddleReturnCount = getTheoryReturnCount(monthMiddleCount, monthMiddleContractCount, firstWeightRatio, secondWeightRatio);
                        departmentMonthMap.put("theoryMiddleReturnCount", theoryMiddleReturnCount);
                        // 中旬理论回复量求和
                        theoryMiddleReturnCountSum = theoryMiddleReturnCountSum + theoryMiddleReturnCount;
                        // 三、 下旬
                        // 当月合同量
                        // 当月提报量
                        Integer monthCountDepartment = salesPlanScItemExtendSDONew.getMonthCount();
                        // 当月部门理论回复量
                        Integer theoryMonthReturnCount = getTheoryReturnCount(monthCountDepartment, monthContractCount, firstWeightRatio, secondWeightRatio);
                        departmentMonthMap.put("theoryMonthReturnCount", theoryMonthReturnCount);
                        // 当月理论回复量求和
                        theoryMonthReturnCountSum = theoryMonthReturnCountSum + theoryMonthReturnCount;

                        // 下旬理论回复量 （当月-上-中）
                        Integer theoryLastReturnCount = theoryMonthReturnCount - theoryMiddleReturnCount- theoryFirstReturnCount;
                        departmentMonthMap.put("theoryLastReturnCount", theoryLastReturnCount);
                        // 下旬理论回复量求和
                        theoryLastReturnCountSum = theoryLastReturnCountSum + theoryLastReturnCount;
                        departmentMap.put(departmentId, departmentMonthMap);
                        list.add(departmentMap);
                    }
                    theoryReturnCountSum.put("theoryFirstReturnCountSum", theoryFirstReturnCountSum);
                    theoryReturnCountSum.put("theoryMiddleReturnCountSum", theoryMiddleReturnCountSum);
                    theoryReturnCountSum.put("theoryLastReturnCountSum", theoryLastReturnCountSum);
                    theoryReturnCountSum.put("theoryMonthReturnCountSum", theoryMonthReturnCountSum);
                    for (SalesPlanStrategyDetailSDO departmentStrategy2 : salesPlanStrategyDetailDepartmentList) {
                        // 部门id
                        String departmentId = departmentStrategy2.getReplyTargetId();
                        // 筛选有策略的部门是否在该组织下
                        boolean flag = departmentSDOForOrg.stream().anyMatch(d -> departmentId.equals(d.getId()));
                        if (!flag) {
                            continue;
                        }
                        // 提报量因子
                        Integer firstWeightRatio = departmentStrategy2.getFirstWeightRatio();
                        // 合同量因子
                        Integer secondWeightRatio = departmentStrategy2.getSecondWeightRatio();
                        SalesPlanStatScItemSDO salesPlanStatScItemSDO = map.get(departmentId);
                        // 部门策略配置多了，实际这个部门没有提报的情况
                        if (Objects.isNull(salesPlanStatScItemSDO)) {
                            continue;
                        }
                        SalesPlanScItemExtendSDO salesPlanScItemExtendSDONew = new SalesPlanScItemExtendSDO();
                        BeanUtils.copyProperties(salesPlanStatScItemSDO, salesPlanScItemExtendSDONew);
                        // 上旬提报量*权重+上旬合同量*权重 合同量根据三询均衡拆分  不过策略里面要告诉哪个是计划量因子，哪个是合同量因子
                        Integer monthContractCount = salesPlanScItemExtendSDONew.getMonthContractCount();
                        // 月份三旬合同量map
                        Map<String, Integer> balanceContractMap = getBalanceContract(salesPlanSDO, monthContractCount);
                        // 一、 上旬
                        //上旬合同量
                        Integer monthFirstContractCount = balanceContractMap.get("monthFirstContractCount");
                        //上旬提报量
                        Integer monthFirstCount = salesPlanScItemExtendSDONew.getMonthFirstCount();
                        // 上旬部门理论回复量
                        Integer theoryFirstReturnCount = getTheoryReturnCount(monthFirstCount, monthFirstContractCount, firstWeightRatio, secondWeightRatio);
                        // 上旬部门理论回复量汇总
                        Integer theoryFirstReturnCountSum1 = theoryReturnCountSum.get("theoryFirstReturnCountSum");
                        // 上旬部门理论回复占比
                        BigDecimal theoryFirstRate = CalculatePercentage.retainTwoBigDecimal(new BigDecimal(theoryFirstReturnCount), new BigDecimal(theoryFirstReturnCountSum1));
                        BigDecimal theoryFirstRateNew = theoryFirstRate.multiply(new BigDecimal(0.01)).setScale(4, BigDecimal.ROUND_HALF_UP);
                        // 部门实际上旬回复量（部门任务量）
                        Integer taskFirstCount = new BigDecimal(monthFirstOrganizationReturnCount).multiply(theoryFirstRateNew).setScale(0, BigDecimal.ROUND_DOWN).intValue();
                        salesPlanScItemExtendSDONew.setMonthFirstReturnCount(taskFirstCount);
                        salesPlanScItemExtendSDONew.setMonthFirstTaskCount(taskFirstCount);

                        // 二 中旬
                        //中旬合同量
                        Integer monthMiddleContractCount = balanceContractMap.get("monthMiddleContractCount");
                        //中旬提报量
                        Integer monthMiddleCount = salesPlanScItemExtendSDONew.getMonthMiddleCount();
                        //中旬部门理论回复量
                        Integer theoryMiddleReturnCount = getTheoryReturnCount(monthMiddleCount, monthMiddleContractCount, firstWeightRatio, secondWeightRatio);
                        //中旬部门理论回复汇总
                        Integer theoryMiddleReturnCountSum1 = theoryReturnCountSum.get("theoryMiddleReturnCountSum");
                        //中旬理论回复占比
                        BigDecimal theoryMiddleRate = CalculatePercentage.retainTwoBigDecimal(new BigDecimal(theoryMiddleReturnCount), new BigDecimal(theoryMiddleReturnCountSum1));
                        BigDecimal theoryMiddleRateNew = theoryMiddleRate.multiply(new BigDecimal(0.01)).setScale(4, BigDecimal.ROUND_HALF_UP);
                        //部门实际中旬回复量（中旬任务量）
                        Integer taskMiddleCount = new BigDecimal(monthMiddleOrganizationReturnCount).multiply(theoryMiddleRateNew).setScale(0, BigDecimal.ROUND_DOWN).intValue();
                        salesPlanScItemExtendSDONew.setMonthMiddleReturnCount(taskMiddleCount);
                        salesPlanScItemExtendSDONew.setMonthMiddleTaskCount(taskMiddleCount);

                        // 三 下旬
                        //当月合同量
                        //当月提报量
                        Integer monthCountDepartment = salesPlanScItemExtendSDONew.getMonthCount();
                        //当月部门理论回复量
                        Integer theoryMonthReturnCount = getTheoryReturnCount(monthCountDepartment, monthContractCount, firstWeightRatio, secondWeightRatio);
                        //当月部门理论回复汇总
                        Integer theoryMonthReturnCountSum1 = theoryReturnCountSum.get("theoryMonthReturnCountSum");
                        //当月理论回复占比
                        BigDecimal theoryMonthRate = CalculatePercentage.retainTwoBigDecimal(new BigDecimal(theoryMonthReturnCount), new BigDecimal(theoryMonthReturnCountSum1));
                        BigDecimal theoryMonthRateNew = theoryMonthRate.multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_HALF_UP);
                        //部门实际当月回复量（当月任务量）
                        Integer taskMonthCount = new BigDecimal(monthOrganizationReturnCount).multiply(theoryMonthRateNew).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                        //下旬 = 当月-上-中
                        int taskLastCount = taskMonthCount - taskFirstCount - taskMiddleCount;
                        salesPlanScItemExtendSDONew.setMonthLastReturnCount(taskLastCount);
                        salesPlanScItemExtendSDONew.setMonthLastTaskCount(taskLastCount);
                        // 部门任务量
                        salesPlanScItemExtendSDONew.setTaskCount(taskFirstCount + taskMiddleCount + taskLastCount);
                        // 计算折前任务金额
                        salesPlanScItemExtendSDONew.setBeforeTaskMoney(salesPlanScItemExtendSDONew.getTaskCount() * salesPlanScItemExtendSDONew.getCostInsuranceFreight());
                        // 计算折后任务金额
                        salesPlanScItemExtendSDONew.calculateTaskMoney(salesPlanSDO.getEstimateDiscount());
                        salesPlanScItemExtendSDONew.calculateTaskSatisfaction();
                        salesPlanScItemExtendSDONew.setId(null);
                        salesPlanScItemExtendSDONew.setModel(SalesPlanModelEnum.PLAN_MODEL.getModel());
                        salesPlanScItemExtendSDONew.setModelId(planId);
                        // 更新状态为待发布
                        salesPlanScItemExtendSDONew.setStatus(SalesPlanStatusEnum.TO_BE_PUBLISHED.getCode());
                        planScItemExtendSDOAllList.add(salesPlanScItemExtendSDONew);
                    }
                }
            }
        }
        // 补偿机制
        // 分子公司的提报量的和
        int sum = salesPlanScItemExtendSDOList.stream().mapToInt(SalesPlanScItemExtendSDO::getMonthCount).sum();
        // 分子公司的回复量和
        int sum1 = salesPlanScItemExtendSDOList.stream().mapToInt(SalesPlanScItemExtendSDO::getMonthFirstReturnCount).sum();
        int sum2 = salesPlanScItemExtendSDOList.stream().mapToInt(SalesPlanScItemExtendSDO::getMonthMiddleReturnCount).sum();
        int sum3 = salesPlanScItemExtendSDOList.stream().mapToInt(SalesPlanScItemExtendSDO::getMonthLastReturnCount).sum();
        // 部门的回复量和
        int sum4 = planScItemExtendSDOAllList.stream().mapToInt(SalesPlanScItemExtendSDO::getMonthFirstReturnCount).sum();
        int sum5 = planScItemExtendSDOAllList.stream().mapToInt(SalesPlanScItemExtendSDO::getMonthMiddleReturnCount).sum();
        int sum6 = planScItemExtendSDOAllList.stream().mapToInt(SalesPlanScItemExtendSDO::getMonthLastReturnCount).sum();

        int company = sum1 + sum2 + sum3;
        int department = sum4 + sum5 + sum6;
        int diff = 0;
        // 回复量大于提报量
        if (company >= sum) {
            diff = sum-department;
        } else {
            diff = company - department;
        }
        SalesPlanScItemExtendSDO salesPlanScItemExtendSDO = planScItemExtendSDOAllList.get(0);
        planScItemExtendSDOAllList.remove(0);
        salesPlanScItemExtendSDO.setMonthLastReturnCount(salesPlanScItemExtendSDO.getMonthLastReturnCount() + diff);
        salesPlanScItemExtendSDO.setMonthLastTaskCount(salesPlanScItemExtendSDO.getMonthLastTaskCount() + diff);
        salesPlanScItemExtendSDO.setTaskCount(salesPlanScItemExtendSDO.getTaskCount() + diff);
        planScItemExtendSDOAllList.add(0,salesPlanScItemExtendSDO);
        log.info("批量新增生成部门任务量入参{}", JSON.toJSONString(planScItemExtendSDOAllList));
        return doProcessPlanScItemExtend(planId, planScItemExtendSDOAllList);
    }

    @EpochTransactional(appCode="bc_order", dataSourceCode = "cr_ots", dataSourceType = "app")
    public Boolean doProcessPlanScItemExtend(String planId, List<SalesPlanScItemExtendSDO> planScItemExtendSDOAllList) {
        //最后批量新增
        Boolean aBoolean = salesPlanScItemExtendRepository.batchCreatePlanScItemExtend(planScItemExtendSDOAllList);
        // 更新发布状态为已生成部门任务量
        SalesPlanSDO updateCheckStatusSalesPlanSDO = new SalesPlanSDO();
        updateCheckStatusSalesPlanSDO.setId(Long.valueOf(planId));
        updateCheckStatusSalesPlanSDO.setCheckStatus(SalesPlanCheckStatusEnum.DECOMPOSE_DEPARTMENT_TASK.getCode());
        salesPlanRepository.editSalesPlan(updateCheckStatusSalesPlanSDO);
        return aBoolean;
    }

    private void checkParam(DispatchPlanScItemRequest dispatchPlanScItemRequest) {
        if (StringUtils.isBlank(dispatchPlanScItemRequest.getPlanId())) {
            throw new ActivityException("OTS-02-004-01-15-001");
        }
    }

    /**
     * 计算部门理论回复量
     *
     * @param monthCount         提报量
     * @param monthContractCount 合同量
     * @param firstWeightRatio   提报因子
     * @param secondWeightRatio  合同因子
     * @return
     */
    private Integer getTheoryReturnCount(Integer monthCount, Integer monthContractCount, Integer firstWeightRatio, Integer secondWeightRatio) {
        BigDecimal firstWeightRatioNew = new BigDecimal(firstWeightRatio).multiply(new BigDecimal(0.0001)).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal secondWeightRatioNew = new BigDecimal(secondWeightRatio).multiply(new BigDecimal(0.0001)).setScale(2, BigDecimal.ROUND_HALF_UP);
        // 部门理论回复量   (部门提报量*提报因子+合同量*合同因子)
        Integer theoryReturnCount = (new BigDecimal(monthCount).multiply(firstWeightRatioNew).setScale(0, BigDecimal.ROUND_HALF_UP))
                .add(new BigDecimal(monthContractCount).multiply(secondWeightRatioNew).setScale(0, BigDecimal.ROUND_HALF_UP)).intValue();
        return theoryReturnCount;
    }

    /**
     * 合同量根据三旬均衡拆分上中下旬（和计划量的拆分一样）
     * salesPlanSDO   计划信息
     * monthContractCount 月份合同量
     * return  上中下旬合同量Map<String, Integer>
     */
    private Map<String, Integer> getBalanceContract(SalesPlanSDO salesPlanSDO, Integer monthContractCount) {
        Map<String, Integer> ContractCountMap = new HashMap();
        BigDecimal sum = salesPlanSDO.getMonthFirstProprtion().add(salesPlanSDO.getMonthMiddleProprtion()).add(salesPlanSDO.getMonthLastProprtion());
        if (new BigDecimal(100).compareTo(sum) == 0) {
            //月度计划有配置三旬比例均衡
            //上旬合同量
            BigDecimal monthFirstProprtion = salesPlanSDO.getMonthFirstProprtion();
            BigDecimal firstCount = monthFirstProprtion.multiply(new BigDecimal(Optional.ofNullable(monthContractCount).orElse(0)));
            Integer monthFirstContractCount = firstCount.divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_DOWN).intValue();
            ContractCountMap.put("monthFirstContractCount", monthFirstContractCount);

            //下旬合同量
            BigDecimal monthLastProprtion = salesPlanSDO.getMonthLastProprtion();
            BigDecimal LastCount = monthLastProprtion.multiply(new BigDecimal(Optional.ofNullable(monthContractCount).orElse(0)));
            Integer monthLastContractCount = LastCount.divide(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_DOWN).intValue();
            ContractCountMap.put("monthLastContractCount", monthLastContractCount);

            //中旬合同量
            Integer monthMiddleContractCount = monthContractCount - (monthFirstContractCount + monthLastContractCount);
            ContractCountMap.put("monthMiddleContractCount", monthMiddleContractCount);
        }
        return ContractCountMap;
    }

    /**
     * 校验计划
     *
     * @param planId
     * @return
     */
    private SalesPlanSDO checkPlan(String planId) {
        QuerySalesPlanRequest querySalesPlanRequest = new QuerySalesPlanRequest();
        querySalesPlanRequest.setId(planId);
        SalesPlanSDO salesPlanSDO = salesPlanRepository.load(querySalesPlanRequest);
        if (Objects.isNull(salesPlanSDO)) {
            throw new FacadeException("OTS-02-002-00-16-001");
        }
//        Integer status = salesPlanSDO.getStatus();
//        if (!SalesPlanStatusEnum.TO_BE_PUBLISHED.getCode().equals(status)) {
//            throw new FacadeException("OTS-02-004-01-15-004");
//        }
        return salesPlanSDO;
    }
}
